/*
 * @(#)ObjectWrapper.java
 *
 *
 *
 * ver 1.0 Aug 17, 2007 ggranum
 */
package org.testfire.model;

import org.testfire.util.DomUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.TypeInfo;

import java.lang.reflect.Constructor;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

public class ObjectWrapper
{

    private static final Map<String, Class> xmlTypeToJavaClassMap = new HashMap<String, Class>( );

    static {
        xmlTypeToJavaClassMap.put( "string", StringWrapper.class);
        xmlTypeToJavaClassMap.put( "date", DateWrapper.class);
        xmlTypeToJavaClassMap.put( "dateTime", DateTimeWrapper.class);
        xmlTypeToJavaClassMap.put( "boolean", BooleanWrapper.class);
        xmlTypeToJavaClassMap.put( "anyURI", AnyURIWrapper.class);
        xmlTypeToJavaClassMap.put( "float", DoubleWrapper.class);
        xmlTypeToJavaClassMap.put( "double", DoubleWrapper.class);
        xmlTypeToJavaClassMap.put( "decimal", DoubleWrapper.class);
        xmlTypeToJavaClassMap.put( "int", IntegerWrapper.class);
        xmlTypeToJavaClassMap.put( "integer", IntegerWrapper.class);
        xmlTypeToJavaClassMap.put( "long", LongWrapper.class );
        xmlTypeToJavaClassMap.put( "short", IntegerWrapper.class);
        xmlTypeToJavaClassMap.put( "byte", ByteWrapper.class);

    }

    private Wrapper wrappedObj;

    public ObjectWrapper( Node node)
    {
        parse(node);
    }


    public void parse(Node el)
    {
        short type =el.getNodeType();
        TypeInfo info = null;
        if( type == Node.ATTRIBUTE_NODE){
            info = ((Attr)el).getSchemaTypeInfo();
        }
        else if(type == Node.ELEMENT_NODE ){
            info = ((Element)el).getSchemaTypeInfo();
        }
        if(info != null){
            String typeName = info.getTypeName();
            Class c = xmlTypeToJavaClassMap.get(typeName);
            if(c != null){
                try
                {
                    Constructor con = c.getConstructor( String.class);
                    wrappedObj = (Wrapper)con.newInstance( el.getNodeValue() );
                }
                catch ( Exception e )
                {
                    throw new IllegalArgumentException( e );
                }

            }
        }
    }

    public String toArgumentString(){
        return wrappedObj.toArgumentString();
    }
    private abstract static class Wrapper {
        Object obj;
        Class objClass;
        boolean quoted;

        public Wrapper(Object obj, Class objClass)
        {
            this(obj, objClass, false );
        }
        public Wrapper(Object obj, Class objClass, boolean isQuoted)
        {
            this.obj = obj;
            this.objClass = objClass;
            quoted = isQuoted;
        }

        /**
         * Most arguments are not quoted, and can safely be returned directly via toString();
         * @return A string that is valid to use as a parameter to a method; e.g.
         * someMethod(int x, String y) requires a call of someMethod(10, "20"). Thus we must return a quoted string
         * for string types, etc.
         */
        String toArgumentString(){
            return quoted ? "\"" + obj.toString() + "\"" : obj.toString();
        }
    }
    private static class StringWrapper extends Wrapper {
        public StringWrapper(String s)
        {
            super( s.replaceAll( Pattern.quote( "\""), "\\\\\""), String.class, true);
        }
    }
    private static class DateWrapper extends Wrapper {
        public DateWrapper(String s)
        {
            super( DomUtil.toJavaDate( s ), Date.class, true);
        }
    }
    private static class DateTimeWrapper extends Wrapper {
        public DateTimeWrapper(String s)
        {
            super( DomUtil.toJavaDate( s ), Date.class, true);
        }
    }
    private static class BooleanWrapper extends Wrapper {
        public BooleanWrapper(String s)
        {
            super( Boolean.valueOf( s ), Boolean.class);
        }
    }

    private static class AnyURIWrapper extends Wrapper {
        public AnyURIWrapper(String s) throws URISyntaxException
        {
            super(s.replaceAll( Pattern.quote( "\""), "\\\\\""), String.class, true);
        }
    }


    private static class DoubleWrapper extends Wrapper {
        public DoubleWrapper(String s)
        {
            super(Double.valueOf( s ), Double.class);
        }
    }
    private static class IntegerWrapper extends Wrapper {
        public IntegerWrapper(String s)
        {
            super(Integer.valueOf( s ), Integer.class);
        }
    }
    private static class LongWrapper extends Wrapper {
        public LongWrapper(String s)
        {
            super(Long.valueOf( s ), Long.class);
        }
    }
    private static class ByteWrapper extends Wrapper {
        public ByteWrapper(String s)
        {
            super(Byte.valueOf( s ), Byte.class);
        }
    }


}

// eof: ObjectWrapper.java